﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Brain.Skinning;
using System;

namespace Brain.Rendering
{
    public class DefaultRenderManager3D : IRenderManager3D
    {
        public GraphicsDevice GraphicsDevice { get; set; }

        public bool ShouldDraw { get; set; }

        public bool ShouldUpdate { get; set; }

        protected List<IWorldObject> Objects;

        internal List<Line3D> Lines;
        internal BasicEffect BasicEffect;

        public List<Action> BeforeRenderActions { get; set; }
        public List<Action> AfterRenderActions { get; set; }

        internal VertexPositionColor[] Vertices;
        public DynamicVertexBuffer VerticesBuffer;

        public BrainModel Cylinder { get; set; }

        // Came from the line Shader
#if WINDOWS
        Byte[] effect = new Byte[1620] { 207, 11, 240, 188, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9, 255, 254, 192, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 87, 111, 114, 108, 100, 0, 122, 0, 3, 0, 0, 0, 2, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 86, 105, 101, 119, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 80, 114, 111, 106, 101, 99, 116, 105, 111, 110, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 104, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 67, 111, 108, 111, 114, 0, 0, 0, 1, 0, 0, 0, 16, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 15, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 80, 97, 115, 115, 49, 0, 0, 0, 11, 0, 0, 0, 84, 101, 99, 104, 110, 105, 113, 117, 101, 49, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 1, 0, 0, 92, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 164, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 120, 1, 0, 0, 116, 1, 0, 0, 147, 0, 0, 0, 0, 0, 0, 0, 144, 1, 0, 0, 140, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 232, 1, 0, 0, 0, 2, 255, 255, 254, 255, 22, 0, 67, 84, 65, 66, 28, 0, 0, 0, 35, 0, 0, 0, 0, 2, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 28, 0, 0, 0, 112, 115, 95, 50, 95, 48, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, 57, 46, 50, 54, 46, 57, 53, 50, 46, 50, 56, 52, 52, 0, 254, 255, 93, 0, 80, 82, 69, 83, 1, 2, 88, 70, 254, 255, 36, 0, 67, 84, 65, 66, 28, 0, 0, 0, 91, 0, 0, 0, 1, 2, 88, 70, 1, 0, 0, 0, 28, 0, 0, 0, 0, 1, 0, 32, 88, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 56, 0, 0, 0, 72, 0, 0, 0, 67, 111, 108, 111, 114, 0, 171, 171, 1, 0, 3, 0, 1, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 120, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, 57, 46, 50, 54, 46, 57, 53, 50, 46, 50, 56, 52, 52, 0, 254, 255, 12, 0, 80, 82, 83, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 18, 0, 67, 76, 73, 84, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 20, 0, 70, 88, 76, 67, 2, 0, 0, 0, 3, 0, 0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 240, 240, 240, 240, 15, 15, 15, 15, 255, 255, 0, 0, 1, 0, 0, 2, 0, 8, 15, 128, 0, 0, 228, 160, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 212, 1, 0, 0, 0, 2, 254, 255, 254, 255, 63, 0, 67, 84, 65, 66, 28, 0, 0, 0, 198, 0, 0, 0, 0, 2, 254, 255, 3, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 32, 191, 0, 0, 0, 88, 0, 0, 0, 2, 0, 8, 0, 4, 0, 0, 0, 100, 0, 0, 0, 116, 0, 0, 0, 180, 0, 0, 0, 2, 0, 4, 0, 4, 0, 0, 0, 100, 0, 0, 0, 116, 0, 0, 0, 185, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 100, 0, 0, 0, 116, 0, 0, 0, 80, 114, 111, 106, 101, 99, 116, 105, 111, 110, 0, 171, 3, 0, 3, 0, 4, 0, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 105, 101, 119, 0, 87, 111, 114, 108, 100, 0, 118, 115, 95, 50, 95, 48, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, 57, 46, 50, 54, 46, 57, 53, 50, 46, 50, 56, 52, 52, 0, 171, 31, 0, 0, 2, 0, 0, 0, 128, 0, 0, 15, 144, 9, 0, 0, 3, 0, 0, 1, 128, 0, 0, 228, 144, 0, 0, 228, 160, 9, 0, 0, 3, 0, 0, 2, 128, 0, 0, 228, 144, 1, 0, 228, 160, 9, 0, 0, 3, 0, 0, 4, 128, 0, 0, 228, 144, 2, 0, 228, 160, 9, 0, 0, 3, 0, 0, 8, 128, 0, 0, 228, 144, 3, 0, 228, 160, 9, 0, 0, 3, 1, 0, 1, 128, 0, 0, 228, 128, 4, 0, 228, 160, 9, 0, 0, 3, 1, 0, 2, 128, 0, 0, 228, 128, 5, 0, 228, 160, 9, 0, 0, 3, 1, 0, 4, 128, 0, 0, 228, 128, 6, 0, 228, 160, 9, 0, 0, 3, 1, 0, 8, 128, 0, 0, 228, 128, 7, 0, 228, 160, 9, 0, 0, 3, 0, 0, 1, 192, 1, 0, 228, 128, 8, 0, 228, 160, 9, 0, 0, 3, 0, 0, 2, 192, 1, 0, 228, 128, 9, 0, 228, 160, 9, 0, 0, 3, 0, 0, 4, 192, 1, 0, 228, 128, 10, 0, 228, 160, 9, 0, 0, 3, 0, 0, 8, 192, 1, 0, 228, 128, 11, 0, 228, 160, 255, 255, 0, 0 };
#endif
#if XBOX
        Byte[] effect = new Byte[1380] {188,240,11,207,0,0,0,16,0,0,0,0,0,0,0,0,254,255,9,1,0,0,1,192,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,87,111,114,108,100,0,0,0,0,0,0,3,0,0,0,3,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,86,105,101,119,0,0,0,0,0,0,0,3,0,0,0,3,0,0,1,48,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,80,114,111,106,101,99,116,105,111,110,0,0,0,0,0,3,0,0,0,1,0,0,1,104,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,67,111,108,111,114,0,0,0,0,0,0,1,0,0,0,16,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,15,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,80,97,115,115,49,0,0,0,0,0,0,11,84,101,99,104,110,105,113,117,101,49,0,0,0,0,0,4,0,0,0,1,0,0,0,3,0,0,0,3,0,0,0,4,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,108,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,212,0,0,0,240,0,0,0,0,0,0,0,0,0,0,1,64,0,0,1,92,0,0,0,0,0,0,0,0,0,0,1,176,0,0,0,0,0,0,0,1,0,0,1,164,0,0,0,0,0,0,0,2,0,0,0,92,0,0,0,0,0,0,1,120,0,0,1,116,0,0,0,93,0,0,0,0,0,0,1,144,0,0,1,140,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,1,0,0,0,0,0,0,0,216,16,42,17,0,0,0,0,180,0,0,0,36,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,148,0,0,0,0,0,0,0,0,0,0,0,108,0,0,0,28,0,0,0,95,255,255,3,0,0,0,0,1,0,0,0,28,0,0,0,0,0,0,0,88,0,0,0,48,0,2,0,0,0,1,0,0,0,0,0,56,0,0,0,72,67,111,108,111,114,0,171,171,0,1,0,3,0,1,0,3,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,112,115,95,51,95,48,0,50,46,48,46,49,49,54,50,54,46,48,0,171,0,0,0,0,0,0,0,36,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,16,1,196,0,34,0,0,0,200,143,192,0,0,192,192,0,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,1,244,16,42,17,1,0,0,1,40,0,0,0,204,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,252,0,0,0,0,0,0,0,0,0,0,0,212,0,0,0,28,0,0,0,198,255,254,3,0,0,0,0,3,0,0,0,28,0,0,0,0,0,0,0,191,0,0,0,88,0,2,0,8,0,4,0,0,0,0,0,100,0,0,0,116,0,0,0,180,0,2,0,4,0,4,0,0,0,0,0,100,0,0,0,116,0,0,0,185,0,2,0,0,0,4,0,0,0,0,0,100,0,0,0,116,80,114,111,106,101,99,116,105,111,110,0,171,0,3,0,3,0,4,0,4,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,105,101,119,0,87,111,114,108,100,0,118,115,95,51,95,48,0,50,46,48,46,49,49,54,50,54,46,48,0,171,171,0,0,0,0,0,0,0,204,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,2,144,0,0,0,3,16,1,16,3,0,0,18,0,194,0,0,0,0,0,96,4,96,10,18,0,18,0,0,0,0,0,0,0,0,3,196,0,34,0,0,0,5,248,0,0,0,0,6,136,0,0,0,0,200,1,0,1,0,167,167,0,175,0,0,0,200,2,0,1,0,167,167,0,175,0,1,0,200,4,0,1,0,167,167,0,175,0,2,0,200,8,0,1,0,167,167,0,175,0,3,0,200,1,0,0,0,167,167,0,175,1,4,0,200,2,0,0,0,167,167,0,175,1,5,0,200,4,0,0,0,167,167,0,175,1,6,0,200,8,0,0,0,167,167,0,175,1,7,0,200,1,128,62,0,167,167,0,175,0,8,0,200,2,128,62,0,167,167,0,175,0,9,0,200,4,128,62,0,167,167,0,175,0,10,0,200,8,128,62,0,167,167,0,175,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0 };
#endif
        Effect LineEffect;

        public DefaultRenderManager3D(GraphicsDevice device)
        {
            BeforeRenderActions = new List<Action>();
            AfterRenderActions = new List<Action>();

#if WINDOWS_PHONE || MONOGAME
            LineEffect = new BasicEffect(device);
#else
            LineEffect = new Effect(device, effect);
#endif
            Cylinder = ModelUtil.GenerateCylinderMesh(1, 1, 32);

            this.GraphicsDevice = device;
            this.ShouldDraw = true;

            this.BasicEffect = new Microsoft.Xna.Framework.Graphics.BasicEffect(device);
            BasicEffect.VertexColorEnabled = true;

            Vertices = new VertexPositionColor[2];
            Vertices[0] = new VertexPositionColor(Vector3.Zero, Color.White);
            Vertices[1] = new VertexPositionColor(Vector3.Forward, Color.White);

            Objects = new List<IWorldObject>();
            Lines = new List<Line3D>();

            BoxVertices = new VertexPositionColor[8];
        }
        public readonly int[] BoxIndices = new int[]
        {
            0, 1,
            1, 2,
            2, 3,
            3, 0,
            0, 4,
            1, 5,
            2, 6,
            3, 7,
            4, 5,
            5, 6,
            6, 7,
            7, 4,
        };
        private VertexPositionColor[] BoxVertices;

       
        public void Update()
        {
        }

        public void StartDraw(GameScreen gs)
        {
        }

        public void FinishDraw(GameScreen gs)
        {

        }

        // O is your object's position
        // P is the position of the object to face
        // U is the nominal "up" vector (typically Vector3.Up)
        // Note: this does not work when O is straight below or straight above P
        Matrix RotateToFace(Vector3 O, Vector3 P, Vector3 U)
        {
            Vector3 D = (O - P);
            Vector3 Right = Vector3.Cross(U, D);
            Right.Normalize();
            Vector3 Backwards = Vector3.Cross(Right, U);
            Vector3.Normalize(ref Backwards, out Backwards);
            Vector3 Up = Vector3.Cross(Backwards, Right);
            Matrix rot = new Matrix(Right.X, Right.Y, Right.Z, 0, Up.X, Up.Y, Up.Z, 0, Backwards.X, Backwards.Y, Backwards.Z, 0, 0, 0, 0, 1);

            return rot;
        }

        public void DrawEverything(Matrix View, Matrix Projection)
        {
            if (Objects == null)
                return;

            GraphicsDevice device = this.GraphicsDevice;
            device.BlendState = BlendState.Opaque;
            device.DepthStencilState = DepthStencilState.Default;

            if (LineEffect is BasicEffect)
            {
                BasicEffect basic = LineEffect as BasicEffect;
                basic.View = View;
                basic.Projection = Projection;
            }
            else
            {
                if (LineEffect != null)
                {
                    LineEffect.Parameters["View"].SetValue(View);
                    LineEffect.Parameters["Projection"].SetValue(Projection);
                }
            }

            for (int i = 0; i < Lines.Count; i++)
            {
                Line3D line = Lines[i];

                LineEffect.Parameters["Color"].SetValue(line.Color.ToVector3());
                if (line.Thickness == 0)
                {
                    Vertices[0].Position = line.Start;
                    Vertices[0].Color = line.Color;

                    Vertices[1].Position = line.End;
                    Vertices[1].Color = line.Color;

                    BasicEffect.View = View;
                    BasicEffect.Projection = Projection;
                    BasicEffect.World = Matrix.Identity;
                    BasicEffect.CurrentTechnique.Passes[0].Apply();

                    device.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList,
                        this.Vertices, 0, 1);
                }
                else
                {
                    BrainModelMesh mesh = Cylinder.Meshes[0];

                    Vector3 dir = Vector3Util.Direction(line.Start, line.End);
                    Matrix m = Matrix.CreateFromAxisAngle(dir, MathHelper.ToRadians(90));

                    float length = Vector3.Distance(line.Start, line.End);

                    Matrix k = Matrix.CreateWorld(line.Start, dir, Vector3.Up);

                    LineEffect.Parameters["World"].SetValue(Matrix.CreateScale(line.Thickness, length, line.Thickness)
                        * Matrix.CreateRotationX(MathHelper.ToRadians(90)) * k *
                        Matrix.CreateTranslation(Vector3.Up * (length / 2f) + k.Forward * (length / 2f)));
                    LineEffect.CurrentTechnique.Passes[0].Apply();

                    device.SetVertexBuffer(mesh.VertexBuffer);
                    device.Indices = mesh.IndexBuffer;

                    device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, mesh.NumVertices, 0, mesh.PrimitiveCount);
                }
            }

            for (int i = 0; i < Objects.Count; i++)
            {
                IWorldObject obj = Objects[i];

                if (obj.BoundingBoxColor != null)
                {
                    // Editor mode, draw Bounding Boxes
                    BasicEffect.View = View;
                    BasicEffect.Projection = Projection;
                    BasicEffect.World = Matrix.Identity;
                    if (obj.BoundingBoxColor != null)
                    {
                        BasicEffect.DiffuseColor = obj.BoundingBoxColor.Value.ToVector3();
                    }

                    Vector3[] boxVertices = obj.BoundingBox.GetCorners();
                    for (int x = 0; x < boxVertices.Length; x++)
                    {
                        BoxVertices[x].Position = boxVertices[x];
                    }

                    BasicEffect.CurrentTechnique.Passes[0].Apply();
#if !SILVERLIGHT
                    device.DrawUserIndexedPrimitives<VertexPositionColor>(
                            PrimitiveType.LineList,
                            BoxVertices,
                            0,
                            8,
                            BoxIndices,
                            0,
                            BoxIndices.Length / 2);
#endif
                }

#if XBOX
                if (obj is XboxAvatar)
                {
                    XboxAvatar avatar = obj as XboxAvatar;
                    if (avatar.Loaded && avatar.Renderer != null)
                    {
                        avatar.Renderer.World = avatar.WorldMatrix;
                        avatar.Renderer.Projection = Projection;
                        avatar.Renderer.View = View;
                        if (avatar is XboxAvatar_CustomAnimation)
                        {
                            avatar.Renderer.Draw((avatar as XboxAvatar_CustomAnimation).AnimationPlayer);
                        }
                        else if (avatar is XboxAvatar_Default)
                        {
                            avatar.Renderer.Draw((avatar as XboxAvatar_Default).Animation);
                        }
                    }
                }
                else
#endif
                    if (obj.Model is SkinnedModel)
                    {
                        SkinnedModel model = obj.Model as SkinnedModel;

                        foreach (ModelMesh mesh in model.Model.Meshes)
                        {
                            foreach (SkinnedEffect effect in mesh.Effects)
                            {
                                effect.World = obj.WorldMatrix;

                                effect.SetBoneTransforms(model.SkinTransforms);

                                effect.View = View;
                                effect.Projection = Projection;
                                effect.EnableDefaultLighting();
                                effect.PreferPerPixelLighting = true;

                                effect.SpecularColor = new Vector3(0.25f);
                                effect.SpecularPower = 16;
                            }

                            mesh.Draw();
                        }
                    }
                    else if (obj.Model is BrainModel)
                    {
                        BrainModel model = obj.Model as BrainModel;
                        DrawBrainModel(obj, model, View, Projection);
                    }
                    else if (obj.RenderingTag is BrainModel)
                    {
                        BrainModel model = obj.RenderingTag as BrainModel;
                        DrawBrainModel(obj, model, View, Projection);
                    }
            }
        }

        public void EndDraw()
        {
            for (int i = 0; i < BeforeRenderActions.Count; i++)
            {
                BeforeRenderActions[i].Invoke();
            }
            if (Engine.Instance.CameraManager != null)
            {
                ICamera3D Camera = Engine.Instance.CameraManager.Camera3D;
                if (Camera != null)
                {
                    if (Engine.Instance.StereoscopicManager == null)
                    {
                        DrawEverything(Camera.View, Camera.Projection);
                    }
                    else
                    {
                        if (Engine.Instance.StereoscopicManager.StereoMode == StereoMode.NoStereo)
                        {
                            DrawEverything(Camera.View, Camera.Projection);
                        }
                        else
                        {
                            Engine.Instance.StereoscopicManager.Draw(Camera, this);
                        }
                    }
                }
            }

            for (int i = 0; i < AfterRenderActions.Count; i++)
            {
                AfterRenderActions[i]();
            }
        }

        protected void DrawBrainModel (IWorldObject obj, BrainModel model, Matrix View, Matrix Projection)
		{
			GraphicsDevice device = Engine.Instance.GraphicsDevice;

            foreach (BrainModelMesh mesh in model.Meshes)
            {
				if (mesh == null)
					continue;

                if (mesh.Effect == null)
                    continue;

                Effect effect = mesh.Effect;
                if (effect is BasicEffect)
                {
                    BasicEffect fx = effect as BasicEffect;
                    fx.EnableDefaultLighting();
                    fx.PreferPerPixelLighting = true;

                    fx.Projection = Projection;
                    fx.View = View;

                    Matrix world = obj.WorldMatrix;
                    if (obj.Model is Model)
                    {
                        Model mod = obj.Model as Model;
                        // Copy any parent transforms.
                        Matrix[] transforms = new Matrix[mod.Bones.Count];
                        mod.CopyAbsoluteBoneTransformsTo(transforms);

                        fx.World = transforms[mesh.BoneParentIndex] * world;
                    }
                    else
                    {
                        fx.World = world;
                    }
                }
                else
                {
                    //continue;
                }

                device.Indices = mesh.IndexBuffer;
                device.SetVertexBuffer(mesh.VertexBuffer);

                int count = effect.CurrentTechnique.Passes.Count;

                for (int p = 0; p < count; p++)
                {
                    effect.CurrentTechnique.Passes[p].Apply();

                    if (mesh.IndexBuffer == null)
                    {
                        device.DrawPrimitives(PrimitiveType.TriangleList, 0, mesh.PrimitiveCount);
                    }
                    else
                    {
                        device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0,
                            mesh.NumVertices, mesh.VertexOffset, mesh.PrimitiveCount);
                    }
                }
            }
        }


        public void Draw()
        {
        }

        public void SubmitWorldObject(IWorldObject obj)
        {
            if (!this.Objects.Contains(obj))
            {
                Objects.Add(obj);

                if (obj.Model is Model)
                {
                    BrainModel model = new BrainModel();
                    Model m = obj.Model as Model;

                    int count = 0;
                    foreach (ModelMesh mesh in m.Meshes)
                    {
                        count += mesh.MeshParts.Count;
                    }

                    model.Meshes = new BrainModelMesh[count];

                    foreach (ModelMesh mesh in m.Meshes)
                    {
                        for (int i = 0; i < mesh.MeshParts.Count; i++)
                        {
                            ModelMeshPart part = mesh.MeshParts[i];
                                                        
                            BrainModelMesh bmesh = new BrainModelMesh();
                            bmesh.BoneParentIndex = mesh.ParentBone.Index;
                            bmesh.Effect = part.Effect;
                            bmesh.IndexBuffer = part.IndexBuffer;
                            bmesh.NumVertices = part.NumVertices;
                            bmesh.PrimitiveCount = part.PrimitiveCount;
                            bmesh.StartIndex = part.StartIndex;
                            bmesh.VertexBuffer = part.VertexBuffer;
                            bmesh.VertexOffset = part.VertexOffset;

                            model.Meshes[i] = bmesh;
                        }
                    }

                    obj.RenderingTag = model;
                }
            }
        }
        public void RemoveWorldObject(IWorldObject obj)
        {
            if (Objects != null)
            {
                Objects.Remove(obj);
            }
        }

        #region not used
        public void SubmitLight(object light)
        {
        }

        public void RemoveLight(object light)
        {
        }
        #endregion

        public void Reset()
        {
            this.Objects.Clear();
            this.Objects.Capacity = 0;

            this.BeforeRenderActions.Clear();
            this.BeforeRenderActions.Capacity = 0;
            this.AfterRenderActions.Clear();
            this.AfterRenderActions.Capacity = 0;
        }
        public void UpdateWorldObjectStatus(IWorldObject worldObject)
        {
        }

        public SerializationData Data { get; set; }

        public void SerializeData(DefaultSerializationManager manager)
        {
        }

        public void DeserializeData(DefaultSerializationManager manager, SerializationData newData)
        {
        }

        public IWorldObject Editor_GetWorldObject(int index)
        {
            return this.Objects[index];

        }

        public int Editor_Count()
        {
            return this.Objects.Count;
        }

        
        public void Submit(object obj)
        {
            if (obj is Line3D)
            {
                Lines.Add(obj as Line3D);
            }
        }

        public void Remove(object obj)
        {
            if (obj is Line3D)
            {
                Lines.Remove(obj as Line3D);
            }
        }

        public void UpdateTerrainVertexBuffer(WorldObject terrain, VertexBuffer buffer)
        {
            VertexPositionNormalTexture[] vertices = terrain.RenderingTag as VertexPositionNormalTexture[];
            buffer.SetData(vertices);
        }

        public void InitializeTerrainDefaultRendering(TerrainWorldObject terrain, bool wipeCPUContent, bool makeTriangles)
        {
            HeightMap HeightMap = terrain.HeightMap;

            if (HeightMap != null)
            {
                int VertexCount = HeightMap.Width * HeightMap.Height;

                VertexPositionNormalTexture[] vertices = new VertexPositionNormalTexture[VertexCount];
                terrain.RenderingTag = vertices;

                float offset = HeightMap.OffsetBetweenHeights;
                for (int x = 0; x < HeightMap.Width; x++)
                {
                    for (int z = 0; z < HeightMap.Height; z++)
                    {
                        float height = HeightMap.Heights[x, z];
                        int index = x + z * HeightMap.Width;
                        vertices[index].Position = new Vector3(x * offset, height, -z * offset);
                        vertices[index].TextureCoordinate = new Vector2((float)x / 30.0f, (float)z / 30.0f);
                    }
                }

                short[] Indices = new short[(HeightMap.Width - 1) * (HeightMap.Height - 1) * 6];
                int counter = 0;
                for (int y = 0; y < HeightMap.Height - 1; y++)
                {
                    for (int x = 0; x < HeightMap.Width - 1; x++)
                    {
                        int lowerLeft = x + y * HeightMap.Width;
                        int lowerRight = (x + 1) + y * HeightMap.Width;
                        int topLeft = x + (y + 1) * HeightMap.Width;
                        int topRight = (x + 1) + (y + 1) * HeightMap.Width;

                        Indices[counter++] = (short)topLeft;
                        Indices[counter++] = (short)lowerRight;
                        Indices[counter++] = (short)lowerLeft;

                        Indices[counter++] = (short)topLeft;
                        Indices[counter++] = (short)topRight;
                        Indices[counter++] = (short)lowerRight;
                    }
                }

                TriangleUtil.Normal(vertices, Indices);

                VertexBuffer VertexBuffer;
                if (Engine.Instance.RunningEditor)
                {
                    VertexBuffer = new DynamicVertexBuffer(Engine.Instance.GraphicsDevice, VertexPositionNormalTexture.VertexDeclaration,
                         vertices.Length, BufferUsage.None);
                }
                else
                {
                    VertexBuffer = new VertexBuffer(Engine.Instance.GraphicsDevice, VertexPositionNormalTexture.VertexDeclaration,
                         vertices.Length, BufferUsage.None);
                }
                VertexBuffer.SetData(vertices);

                IndexBuffer IndexBuffer;
                if (Engine.Instance.RunningEditor)
                {
                    IndexBuffer = new DynamicIndexBuffer(Engine.Instance.GraphicsDevice,
                        IndexElementSize.SixteenBits, Indices.Length, BufferUsage.None);
                }
                else
                {
                    IndexBuffer = new IndexBuffer(Engine.Instance.GraphicsDevice,
                        IndexElementSize.SixteenBits, Indices.Length, BufferUsage.None);
                }
                IndexBuffer.SetData(Indices);


                BrainModel model = new BrainModel();

                BrainModelMesh mesh = new BrainModelMesh();
                mesh.VertexBuffer = VertexBuffer;
                mesh.IndexBuffer = IndexBuffer;
                mesh.Effect = new BasicEffect(Engine.Instance.GraphicsDevice);
                mesh.NumVertices = VertexBuffer.VertexCount;
                mesh.PrimitiveCount = Indices.Length / 3;
                mesh.StartIndex = 0;
                mesh.VertexOffset = 0;

                model.Meshes = new BrainModelMesh[1];
                model.Meshes[0] = mesh;

                terrain.Model = model;

                if (makeTriangles)
                {
                    terrain.Indices = Indices;
                    terrain.MakeTriangles();
                    terrain.Indices = null;
                }

                if (wipeCPUContent)
                {
                    Indices = null;
                }
                else
                {
                    terrain.Indices = Indices;
                }
            }
        }

        public Vector3 GetTerrainVertex(WorldObject terrain, int index)
        {
            VertexPositionNormalTexture[] vertices = terrain.RenderingTag as VertexPositionNormalTexture[];
            return vertices[index].Position;
        }

        public void Editor_UpdateTerrainVertex(WorldObject terrain, int index, Vector3 newPos, Vector2 newTexCoord)
        {
            VertexPositionNormalTexture[] vertices = terrain.RenderingTag as VertexPositionNormalTexture[];
            vertices[index].Position = newPos;
            vertices[index].TextureCoordinate = newTexCoord;
        }



    }
}
